(function(){
    function GVMap(elements, params){
        this.el = elements
        this.params = {
            draggable: false,
            icon: null
        }
        this.updateParams(params)
    }
    GVMap.prototype.updateParams = function(params){
        for(key in params){
            if(undefined != this.params[key]){
                this.params[key] = params[key]
            }
        }
    }
    GVMap.prototype.auto = function(){
        if(this.isCompatible()){
            for(var i = 0; i < this.el.length; i++){
                var obj = this.el[i]
                var jObj = jQuery(obj)
                if(!this.isLatLng(jObj)){
                    if(!this.isQuery(jObj)){
                        if(!this.isRoute(jObj)){
                            this.query(GVMap.option.query, obj)
                        }
                    }
                }
            }
        }
    }
    GVMap.prototype.init = function(obj){
        var jObj = jQuery(obj)
        var type = this.getMapType(jObj)
        var zoom = this.getZoomLevel(jObj)
        var control = this.getControl(jObj)
        obj.params = {
            icon: this.getIcon(jObj),
            draggable: this.params.draggable
        }
        obj.geocoder = new GClientGeocoder()
        obj.map = new GMap2(obj)
        obj.map.setMapType(type)
        obj.map.addControl(control)
    }
    GVMap.prototype.getIcon = function(){
        var icon = new GIcon(G_DEFAULT_ICON)
        if(null != this.params.icon){
            icon.image = this.params.icon
        }
        icon.shadowSize.width = 0
		icon.shadowSize.height = 0
        return icon
    }
    GVMap.prototype.isLatLng = function(el){
        if(el.attr('data-latitude') != null && el.attr('data-longitude') != null){
            this.latLng(el.attr('data-latitude'), el.attr('data-longitude'), el[0])
            return true
        }
        return false
    }
    GVMap.prototype.latLng = function(latitude, longitude, obj){
        obj = obj || this.el[0]
        this.init(obj)
        var zoom = this.getZoomLevel(jQuery(obj))
        obj.map.setCenter(new GLatLng(Number(latitude), Number(longitude)), zoom)
    }
    GVMap.prototype.isQuery = function(el){
        if(el.attr('data-query') != null){
            this.query(el.attr('data-query'), el[0])
            return true
        }
        return false
    }
    GVMap.prototype.query = function(query, obj){
        obj = obj || this.el[0]
        this.init(obj)
        var zoom = this.getZoomLevel(jQuery(obj))
        var gmap = this
        obj.geocoder.getLatLng(query, function(point){
		    if (!point) {
			    alert(GVMap.messages.addressNotFound + ': ' + query)
                return
		    }
            obj.map.setCenter(point, zoom)
            var mark = new GMarker(point, obj.params)
            GEvent.addListener(mark, "click", function(){
                gmap.onclick(obj, mark)
            })
            if(obj.params.draggable){
                GEvent.addListener(mark, "dragstart", function(){
                    obj.map.closeInfoWindow()
                })
                GEvent.addListener(mark, "dragend", function(){
                    gmap.ondrop(obj, mark)
                })
            }         
            obj.map.addOverlay(mark)
	    })
	    return this
    }
    GVMap.prototype.isRoute = function(el){
        if(el.attr('data-from') != null && el.attr('data-to') != null){
            this.route(el.attr('data-from'), el.attr('data-to'), el[0])
            return true
        }
        return false
    }
    GVMap.prototype.route = function(from, to, obj){
        obj = obj || this.el[0]
        this.init(obj)
        var directions = new GDirections(obj.map)
        GEvent.addListener(directions, "error", function(){ 
            if(directions.getStatus().code == G_GEO_UNKNOWN_ADDRESS){
                alert(GVMap.messages.addressNotFound)
            } else if (directions.getStatus().code == G_GEO_MISSING_QUERY){
                alert(GVMap.messages.fillInAllFields)
            }
        })
        directions.load("from: " + from + " to: " + to, {locale: obj.locale})
    }
    GVMap.prototype.getMapType = function(el){
        var type = el.attr('data-type') || GVMap.option.type
        switch(type){
            case 'normal': return G_NORMAL_MAP;
            case 'satellite': return G_SATELLITE_MAP;
            case 'hybrid': return G_HYBRID_MAP;
            default: return G_NORMAL_MAP;
        }
    }
    GVMap.prototype.getZoomLevel = function(el){
        return Number(el.attr('data-zoom') || GVMap.option.zoom)
    }
    GVMap.prototype.getControl = function(el){
        var control = el.attr('data-control') || GVMap.option.control
        switch(control){
            case 'small': return new GSmallMapControl();
            case 'large': return new GLargeMapControl();
            default: return new GSmallMapControl();
        }
    }
    GVMap.prototype.isCompatible = function(){
        if(typeof(GBrowserIsCompatible) == "undefined" || !GBrowserIsCompatible()){
            alert(GVMap.messages.incompatible)
            return false
        }
        return true
    }
    GVMap.prototype.getPlaceHolder = function(obj, mark){
        var placeholder = jQuery(obj).attr('placeholder')
        if(null == placeholder){
            if(null != jQuery(obj).attr('data-query')){
                placeholder = jQuery(obj).attr('data-query')
            }
        }
        return placeholder
    }
    GVMap.prototype.onclick = function(obj, mark){
        var placeholder = this.getPlaceHolder(obj, mark)
        if(null == placeholder){
            placeholder = GVMap.messages.emptyBallon
        }
        mark.openInfoWindowHtml(placeholder)
    }
    GVMap.prototype.ondrop = function(obj, mark){
        var placeholder = this.getPlaceHolder(obj, mark)
        if(null == placeholder){
            placeholder = GVMap.messages.emptyBallon
        }
        mark.openInfoWindowHtml(placeholder)
    }
    GVMap.prototype.center = function(query, obj){
        obj = obj || this.el[0]
        this.init(obj)
        var zoom = this.getZoomLevel(jQuery(obj))
        var gmap = this
        obj.geocoder.getLatLng(query, function(point){
		    if (!point) {
			    alert(GVMap.messages.addressNotFound + ': ' + query)
                return
		    }
            obj.map.setCenter(point, zoom)
	    })
	    return this
    }
    GVMap.prototype.links = function(selector, onEvent){
        onEvent = onEvent || 'click'
        var gmap = this
	    var element = this.el[0]
	    var map = element.map
        var geocoder = element.geocoder
        var params = this.params
        if(window.location.hash != ""){
            jQuery('.gvmap-selected').removeClass('gvmap-selected')
            jQuery(selector + '[href$='+ window.location.hash +']').addClass('gvmap-selected')
        }
        jQuery(selector).live(onEvent, function(e){
            var point = this.mark.getPoint()
            map.setCenter(point)
            gmap.onclick(this, this.mark)
        })
        jQuery(selector).each(function(index, obj){
            if(null != jQuery(obj).attr('data-query')){
                var query = jQuery(obj).attr('data-query')
                geocoder.getLatLng(query, function(point){
        		    if (!point) {
        			    alert(GVMap.messages.addressNotFound + ': ' + query)
                        return
        		    }
                    var mark = new GMarker(point, params)
                    GEvent.addListener(mark, "click", function(){
                        gmap.onclick(obj, mark)
                    })
                    if(params.draggable){
                        GEvent.addListener(mark, "dragstart", function(){
                            map.closeInfoWindow()
                        })
                        GEvent.addListener(mark, "dragend", function(){
                            gmap.ondrop(obj, mark)
                        })
                    }         
                    map.addOverlay(mark)
                    mark.obj = obj
                    obj.mark = mark
                    if(jQuery(obj).hasClass('gvmap-selected')){
                        jQuery(obj)[onEvent]()
                    }
        	    })
            } else {
                if(null != jQuery(obj).attr('data-latitude') && null != jQuery(obj).attr('data-longitude')){
                    var latitude = jQuery(obj).attr('data-latitude')
                    var longitude = jQuery(obj).attr('data-longitude')
                    var point = new GLatLng(Number(latitude), Number(longitude))
                    var mark = new GMarker(point, params)
                    GEvent.addListener(mark, "click", function(){
                        gmap.onclick(obj, mark)
                    })
                    if(params.draggable){
                        GEvent.addListener(mark, "dragstart", function(){
                            map.closeInfoWindow()
                        })
                        GEvent.addListener(mark, "dragend", function(){
                            gmap.ondrop(obj, mark)
                        })
                    }         
                    map.addOverlay(mark)
                    mark.obj = obj
                    obj.mark = mark
                    if(jQuery(obj).hasClass('gvmap-selected')){
                        jQuery(obj)[onEvent]()
                    }
                }
            }
        })
    }
    GVMap.option = {
        zoom: 15,
        type: 'normal',
        control: 'small',
        query: 'São Paulo - Brasil'
    }
    GVMap.messages = {
        incompatible: 'Seu navegador não é compatível com o Google Maps',
        addressNotFound: 'Endereço não encontrado',
        fillInAllFields: 'Preencha todos os campos',
        emptyBallon: 'Nenhuma mensagem para este balão'
    }

    if(undefined != jQuery){
        jQuery.fn.gvmap = function(params){
            return new GVMap(this, params)
        }
    }
})()